package com.roncoo.education.course.service.auth.biz;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import javax.validation.constraints.NotNull;

import org.springframework.stereotype.Component;

import com.roncoo.education.common.config.ThreadContext;
import com.roncoo.education.common.core.base.BaseException;
import com.roncoo.education.common.core.base.Result;
import com.roncoo.education.common.core.enums.BuyTypeEnum;
import com.roncoo.education.common.core.enums.FreeEnum;
import com.roncoo.education.common.core.enums.StatusIdEnum;
import com.roncoo.education.common.polyv.PolyvVodUtil;
import com.roncoo.education.common.polyv.vod.CallbackVodAuthCode;
import com.roncoo.education.common.polyv.vod.req.PlayConfigReq;
import com.roncoo.education.common.polyv.vod.resp.PolyvPlayResponse;
import com.roncoo.education.common.service.BaseBiz;
import com.roncoo.education.course.dao.CourseChapterDao;
import com.roncoo.education.course.dao.CourseChapterPeriodDao;
import com.roncoo.education.course.dao.CourseDao;
import com.roncoo.education.course.dao.ResourceDao;
import com.roncoo.education.course.dao.UserCourseDao;
import com.roncoo.education.course.dao.UserStudyDao;
import com.roncoo.education.course.dao.impl.mapper.entity.CourseChapter;
import com.roncoo.education.course.dao.impl.mapper.entity.CourseChapterPeriod;
import com.roncoo.education.course.dao.impl.mapper.entity.Resource;
import com.roncoo.education.course.dao.impl.mapper.entity.UserCourse;
import com.roncoo.education.course.dao.impl.mapper.entity.UserStudy;
import com.roncoo.education.course.service.auth.req.AuthCourseSignReq;
import com.roncoo.education.course.service.auth.resp.AuthCourseSignResp;
import com.roncoo.education.course.service.biz.resp.CourseChapterResp;
import com.roncoo.education.system.feign.interfaces.IFeignSysConfig;
import com.roncoo.education.system.feign.interfaces.vo.VodConfig;

import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;

/**
 * AUTH-课程信息
 *
 * @author wujing
 */
@Component
@RequiredArgsConstructor
public class AuthCourseBiz extends BaseBiz {

    @NotNull
    private final CourseDao dao;
    @NotNull
    private final CourseChapterDao chapterDao;    
    @NotNull
    private final CourseChapterPeriodDao periodDao;
    @NotNull
    private final ResourceDao resourceDao;
    @NotNull
    private final UserCourseDao userCourseDao;
    @NotNull
    private final UserStudyDao userStudyDao;

    @NotNull
    private final IFeignSysConfig feignSysConfig;

    public Result<AuthCourseSignResp> sign(AuthCourseSignReq req, long userId) {
        if (ObjectUtil.isNotEmpty(req.getCourseId())) {
            // 若课程ID存在，则获取该课程的最新学习课时
            UserStudy userStudy = userStudyDao.getByCourseIdForLast(userId, req.getCourseId());
            if (ObjectUtil.isNotNull(userStudy)) {
                req.setPeriodId(userStudy.getPeriodId());
            } else {
            	CourseChapterPeriod firstPeriod = getFirstPeriodByCourseId(req.getCourseId());
            	if (firstPeriod != null) {
            		req.setPeriodId(firstPeriod.getId());
            	}                
            }
            
            if (req.getPeriodId() == null) {
            	return Result.error("该课程尚未发布视频，请静待更新..");
            }
        }
        CourseChapterPeriod period = periodDao.getById(req.getPeriodId());
        if (ObjectUtil.isEmpty(period) || period.getStatusId().equals(StatusIdEnum.NO.getCode())) {
            return Result.error("该课时不存在或不可用");
        }
//        if (ObjectUtil.isEmpty(period.getResourceId())) {
//            return Result.error("该课时没设置资源");
//        }
//        Resource resource = resourceDao.getById(period.getResourceId());
//        if (ObjectUtil.isEmpty(resource) || resource.getResourceType().equals(ResourceTypeEnum.DOC.getCode())) {
//            return Result.error("资源类型不正确");
//        }
//        if (!resource.getVideoStatus().equals(VideoStatusEnum.SUCCES.getCode())) {
//            return Result.error("资源暂不可用");
//        }

        if (ObjectUtil.isEmpty(period.getMainResourceUrl())) {
        	return Result.error("未匹配到课程资源，请静待更新..");
      	}
        
        if (!check(period, userId)) {
            return Result.error("没购买，不允许播放");
        }
        // 可以播放
        UserStudy userStudy = userStudyDao.getByPeriodIdAndUserId(req.getPeriodId(), userId);
        if (ObjectUtil.isEmpty(userStudy)) {
            userStudy = new UserStudy();
            userStudy.setCourseId(period.getCourseId());
            userStudy.setChapterId(period.getChapterId());
            userStudy.setPeriodId(period.getId());
            userStudy.setUserId(userId);
            userStudy.setProgress(BigDecimal.ZERO);
            userStudyDao.save(userStudy);
        }

        AuthCourseSignResp resp = new AuthCourseSignResp();
        resp.setStartTime(userStudy.getProgress().multiply(new BigDecimal(period.getMainResourceLength())).divide(BigDecimal.valueOf(100)).longValue());
        resp.setStudyId(userStudy.getId());
        resp.setPlayPeriod(period);
//        resp.setPeriodId(req.getPeriodId());
//        resp.setResourceId(resource.getId());
//        resp.setVid(resource.getVideoVid());
//        resp.setResource(resource);
        // 播放参数
        // polyvSign(req, resource, resp);
        return Result.success(resp);
    }

    // 超找每门课的第一个视频课程
    private CourseChapterPeriod getFirstPeriodByCourseId(long courseId) {
        List<CourseChapter> chapterList = chapterDao.listByCourseIdAndStatusId(courseId, StatusIdEnum.YES.getCode());
        
        List<CourseChapterPeriod> periodList = periodDao.listByCourseIdAndStatusId(courseId, StatusIdEnum.YES.getCode());
        Map<Long, List<CourseChapterPeriod>> map = periodList.stream().collect(Collectors.groupingBy(CourseChapterPeriod::getChapterId, Collectors.toList()));

        if (chapterList != null && chapterList.size() > 0) {        	
        	for (CourseChapter chapter : chapterList) {
        		List<CourseChapterPeriod> _periodlist = map.get(chapter.getId());
        		if (_periodlist != null && _periodlist.size() > 0) {
        			for (CourseChapterPeriod period : _periodlist) {
        				if (ObjectUtil.isNotEmpty(period.getMainResourceUrl())) {
        					return period;
        				}
        			}       
        		}
        	}
        }
        
        return null;
    }
    
    private void polyvSign(AuthCourseSignReq req, Resource resource, AuthCourseSignResp resp, long userId) {
        PlayConfigReq polyvSign = new PlayConfigReq();
        polyvSign.setViewerIp(req.getClientIp());
        polyvSign.setViewerId(Long.toString(userId));
        polyvSign.setVid(resource.getVideoVid());

        // 获取code
        CallbackVodAuthCode authCode = new CallbackVodAuthCode();
        authCode.setPeriodId(req.getPeriodId());
        authCode.setShowText("领课开源");
        authCode.setUserId(userId);
        polyvSign.setCallbackVodAuthCode(authCode);

        VodConfig vodConfig = feignSysConfig.getVod();

        PolyvPlayResponse polyvSignResponse = PolyvVodUtil.getSignForPlay(vodConfig.getPolyvUserId(), vodConfig.getPolyvSecretKey(), polyvSign);
        if (ObjectUtil.isEmpty(polyvSignResponse)) {
            throw new BaseException("系统繁忙，请重试");
        }
//        resp.setTs(polyvSignResponse.getTs());
//        resp.setSign(polyvSignResponse.getSign());
//        resp.setToken(polyvSignResponse.getToken());
//        resp.setCode(polyvSignResponse.getCode());
    }

    private Boolean check(CourseChapterPeriod period, long userId) {
        UserCourse userCourse = userCourseDao.getByCourseIdAndUserId(period.getCourseId(), userId);
        if (ObjectUtil.isEmpty(userCourse)) {
            if (period.getIsFree().equals(FreeEnum.FREE.getCode())) {
                // 免费课程不需要购买，直接可以观看
                userCourse = new UserCourse();
                userCourse.setUserId(userId);
                userCourse.setCourseId(period.getCourseId());
                userCourse.setBuyType(BuyTypeEnum.FREE.getCode());
                userCourseDao.save(userCourse);
                return true;
            }
            return false;
        }
        return true;
    }
}
